home *** CD-ROM | disk | FTP | other *** search
- /* GNUPLOT - latex.trm */
- /*
- * Copyright (C) 1990
- *
- * Permission to use, copy, and distribute this software and its
- * documentation for any purpose with or without fee is hereby granted,
- * provided that the above copyright notice appear in all copies and
- * that both that copyright notice and this permission notice appear
- * in supporting documentation.
- *
- * Permission to modify the software is granted, but not the right to
- * distribute the modified code. Modifications are to be distributed
- * as patches to released version.
- *
- * This software is provided "as is" without express or implied warranty.
- *
- * This file is included by ../term.c.
- *
- * This terminal driver supports:
- * LaTeX pictures (latex).
- * LaTeX pictures with emTeX specials (emtex).
- *
- * AUTHORS
- * David Kotz, Russell Lang
- *
- * send your comments or suggestions to (pixar!info-gnuplot@sun.com).
- *
- */
-
- /* modified to optimize use of \rule for long lines */
-
- /* the following LATEX driver has been modified by
- Russell Lang, eln272v@monu1.cc.monash.oz from the
- GnuTeX 1.3 driver by David Kotz, David.Kotz@Dartmouth.edu.
- Since then it has been further extended by David Kotz.
- EmTeX driver by Russell Lang. */
-
-
- #define LATEX_PTS_PER_INCH (72.27)
- #define DOTS_PER_INCH (300) /* resolution of printer we expect to use */
- #define LATEX_UNIT (LATEX_PTS_PER_INCH/DOTS_PER_INCH) /* dot size in pt */
-
- /* 5 inches wide by 3 inches high (default) */
- #define LATEX_XMAX (5*DOTS_PER_INCH) /* (LATEX_PTS_PER_INCH/LATEX_UNIT*5.0) */
- #define LATEX_YMAX (3*DOTS_PER_INCH) /* (LATEX_PTS_PER_INCH/LATEX_UNIT*3.0) */
-
- #define LATEX_HTIC (5*DOTS_PER_INCH/72) /* (5./LATEX_UNIT) */
- #define LATEX_VTIC (5*DOTS_PER_INCH/72) /* (5./LATEX_UNIT) */
- #define LATEX_HCHAR (DOTS_PER_INCH*53/10/72) /* (5.3/LATEX_UNIT) */
- #define LATEX_VCHAR (DOTS_PER_INCH*11/72) /* (11./LATEX_UNIT) */
-
- static int LATEX_posx;
- static int LATEX_posy;
- static enum JUSTIFY latex_justify=LEFT;
- static int latex_angle=0;
-
- /* Default line-drawing character */
- /* the definition of plotpoint varies with linetype */
- #define LATEX_DOT "\\usebox{\\plotpoint}"
- #define LATEX_TINY_DOT "\\rule{.1pt}{.1pt}" /* for dots plot style */
-
- /* POINTS */
- #define LATEX_POINT_TYPES 12 /* we supply more point types */
- static char *LATEX_points[] = {
- "\\raisebox{-1.2pt}{\\makebox(0,0){$\\Diamond$}}",
- "\\makebox(0,0){$+$}",
- "\\raisebox{-1.2pt}{\\makebox(0,0){$\\Box$}}",
- "\\makebox(0,0){$\\times$}",
- "\\makebox(0,0){$\\triangle$}",
- "\\makebox(0,0){$\\star$}",
- "\\circle{12}", "\\circle{18}", "\\circle{24}",
- "\\circle*{12}", "\\circle*{18}", "\\circle*{24}"
- };
-
- /* LINES */
- static float LATEX_size = 0; /* current thick of line in points */
- static float LATEX_dotspace = 0; /* current dotspace of line in points */
- #define LATEX_LINE_TYPES 6 /* number of line types below */
- #define LATEX_THIN_LINE 0 /* the thinnest solid line type */
- static struct {
- float size; /* size of dot, or thick of line in points */
- float dotspace; /* inter-dot space in points; 0 for lines */
- } LATEX_lines[] = {
- {.35, 0.0}, /* thin solid line */
- {.7, 0.0}, /* thick solid line */
- {1.0, 0.0}, /* Thick solid line */
- {.5, 5.0}, /* dotted line */
- {.5, 9.0}, /* widely dotted line */
- {.5, 13.0} /* really widely dotted line */
- };
- /* for drawing dotted and solid lines */
- static void LATEX_dot_line();
- static void LATEX_solid_line();
- static void LATEX_rule();
- static void LATEX_flushdot();
- #define LATEX_flushrule() LATEX_rule(2, 0.,0.,0.,0.) /* flush old rule */
- static BOOLEAN LATEX_moved = TRUE; /* pen is up after move */
- static float LATEX_dotsize; /* size of LATEX_DOT in units */
- static BOOLEAN LATEX_needsdot = FALSE;/* does dotted line need termination? */
-
- #ifdef EMTEX
- BOOLEAN emtex=FALSE; /* not currently using emtex */
- static void EMTEX_solid_line();
- #endif
-
- /* ARROWS */
- /* the set of non-vertical/non-horizontal LaTeX vector slopes */
- /* except negatives - they are handled specially */
- static struct vslope {
- int dx, dy;
- } LATEX_slopes[] = {
- {1,1}, {1,2}, {1,3}, {1,4},
- {2,1}, {2,3},
- {3,1}, {3,2}, {3,4},
- {4,1}, {4,3},
- {0,0} /* terminator */
- };
- static void best_latex_arrow(); /* figure out the best arrow */
-
- LATEX_init()
- {
- #ifdef EMTEX
- emtex = FALSE;
- #endif
- LATEX_posx = LATEX_posy = 0;
- fprintf(outfile, "%% GNUPLOT: LaTeX picture\n");
- fprintf(outfile, "\\setlength{\\unitlength}{%fpt}\n", LATEX_UNIT);
- fprintf(outfile,
- "\\ifx\\plotpoint\\undefined\\newsavebox{\\plotpoint}\\fi\n");
- LATEX_linetype(-1);
- }
-
-
- LATEX_scale(xs, ys)
- double xs, ys; /* scaling factors */
- {
- register struct termentry *t = &term_tbl[term];
-
- /* we change the table for use in graphics.c and LATEX_graphics */
- t->xmax = (unsigned int)(LATEX_XMAX * xs);
- t->ymax = (unsigned int)(LATEX_YMAX * ys);
-
- return(TRUE);
- }
-
- LATEX_graphics()
- {
- register struct termentry *t = &term_tbl[term];
-
- fprintf(outfile, "\\begin{picture}(%d,%d)(0,0)\n", t->xmax, t->ymax);
- fprintf(outfile, "\\tenrm\n");
- }
-
-
- LATEX_text()
- {
- LATEX_flushrule();
- LATEX_flushdot();
- fprintf(outfile, "\\end{picture}\n");
- LATEX_posx = LATEX_posy = 0; /* current position */
- LATEX_moved = TRUE; /* pen is up after move */
- }
-
- LATEX_linetype(linetype)
- int linetype;
- {
- float size;
-
- if (linetype >= LATEX_LINE_TYPES)
- linetype %= LATEX_LINE_TYPES;
-
- #ifdef EMTEX
- if (!emtex)
- #endif
- LATEX_flushrule();
- LATEX_flushdot();
-
- /* Find the new desired line thickness. */
- /* negative linetypes (for axes) use a thin line */
- /* only relevant for drawing axes/border in 3d */
- size = (linetype >= 0 ? LATEX_lines[linetype].size
- : LATEX_lines[LATEX_THIN_LINE].size);
-
- /* If different from current size, redefine \plotpoint */
- if (size != LATEX_size) {
- fprintf(outfile,
- "\\sbox{\\plotpoint}{\\rule[%.3fpt]{%.3fpt}{%.3fpt}}%%\n",
- -size/2, size, size);
- #ifdef EMTEX
- if (emtex) /* change line width */
- fprintf(outfile, "\\special{em:linewidth %.1fpt}%%\n", size);
- #endif
- }
-
- LATEX_size = size;
- LATEX_dotsize = size / LATEX_UNIT;
- LATEX_dotspace = (linetype >= 0) ? LATEX_lines[linetype].dotspace : 0;
- LATEX_moved = TRUE; /* reset */
- }
-
- LATEX_move(x,y)
- unsigned int x,y;
- {
- LATEX_flushdot();
-
- LATEX_posx = x;
- LATEX_posy = y;
- LATEX_moved = TRUE; /* reset */
- }
-
-
- LATEX_point(x,y, number) /* version of line_and_point */
- unsigned int x,y;
- int number; /* type of point */
- {
- LATEX_move(x,y);
-
- /* Print the character defined by 'number'; number < 0 means
- to use a dot, otherwise one of the defined points. */
- fprintf(outfile, "\\put(%d,%d){%s}\n", x, y,
- (number < 0 ? LATEX_TINY_DOT
- : LATEX_points[number % LATEX_POINT_TYPES]));
- }
-
-
- LATEX_vector(ux,uy)
- unsigned int ux,uy;
- {
- if (LATEX_dotspace == 0.0) {
- /* solid line */
- #ifdef EMTEX
- if (emtex)
- EMTEX_solid_line(LATEX_posx, (int)ux, LATEX_posy, (int)uy);
- else
- #endif
- LATEX_solid_line(LATEX_posx, (int)ux, LATEX_posy, (int)uy);
- } else
- /* dotted line */
- LATEX_dot_line(LATEX_posx, (int)ux, LATEX_posy, (int)uy);
-
- LATEX_posx = ux;
- LATEX_posy = uy;
- }
-
- static void
- LATEX_solid_line(x1,x2, y1,y2)
- int x1,x2, y1,y2;
- {
- float slope;
- int inc;
- float next;
- float x,y;
- int code; /* possibly combine with previous rule */
-
- /* we draw a solid line using the current line thickness (size) */
- /* we do it with lots of \\rules */
-
- if (x1 == x2 && y1 == y2) { /* zero-length line - just a dot */
- if (LATEX_moved) {
- LATEX_flushrule();
- /* plot a dot */
- fprintf(outfile, "\\put(%u,%u){%s}\n", x1, y1, LATEX_DOT);
- }
- } else {
- code = (LATEX_moved ? 0 : 1); /* no combine after move */
- if (x1 == x2) /* vertical line - special case */
- LATEX_rule(code, (double)x1, (double)y1,
- LATEX_dotsize, (double)y2-y1);
- else if (y1 == y2) /* horizontal line - special case */
- LATEX_rule(code, (double)x1, (double)y1, (double)x2-x1,
- LATEX_dotsize);
- else {
- slope = ((float)y2-y1)/((float)x2-x1);
- if (abs(slope) <= 1.0) {
- /* longer than high */
- inc = sign(y2-y1);
- for (x = x1, y = y1; (y2-y)*inc >= 0; y += inc) {
- next = inc/slope + x;
- if ((x2>x1 && next > x2) || (x2<x1 && next < x2)) {
- LATEX_rule(code, x,y, x2-x, LATEX_dotsize);
- break;
- } else {
- LATEX_rule(code, x,y, next-x, LATEX_dotsize);
- x = next;
- }
- code = 0;
- }
- } else {
- /* higher than long */
- inc = sign(x2-x1);
- for (x = x1, y = y1; (x2-x)*inc >= 0; x += inc) {
- next = inc*slope + y;
- if ((y2>y1 && next > y2) || (y2<y1 && next < y2)) {
- LATEX_rule(code, x,y, LATEX_dotsize, y2-y);
- break;
- } else {
- LATEX_rule(code, x,y, LATEX_dotsize, next-y);
- y = next;
- }
- code = 0;
- }
- }
- }
- }
- LATEX_moved = FALSE;
- }
-
- /* Draw a \rule. Width or height may be negative; we can correct.
- * The rule is never output immediately. The previous rule is output
- * as-is if code is 0, and the previous rule is
- * combined with the current rule (if possible) if code is 1.
- * The previous rule is output, and the new one ignored, if code is 2.
- */
- static void
- LATEX_rule(code, x,y, width, height)
- int code; /* how do we treat this rule? */
- double x, y;
- double width;
- double height;
- {
- static float lastx, lasty;
- static float lastw, lasth;
- static BOOLEAN valid = FALSE; /* is 'last' data valid? */
- BOOLEAN combine = (code == 1);
- BOOLEAN flush = (code == 2);
-
- if (!flush)
- if (width == 0 || height == 0)
- return; /* ignore this rule */
-
- if (valid && combine) {
- /* try to combine new rule with old rule */
- if ((int)lastx == (int)x && lastw == width) { /* vertical rule */
- if (lasth * height >= 0) { /* same sign */
- lasth += height;
- return;
- }
- } else if ((int)lasty == (int)y && lasth == height){ /* horiz rule */
- if (lastw * width >= 0) { /* same sign */
- lastw += width;
- return;
- }
- }
- /* oh well, output last and remember the new one */
- }
-
- if (valid) {
- /* output the rule */
- if (lastw < 0) {
- lastx += lastw;
- lastw = -lastw;
- }
- if (lasth < 0) {
- lasty += lasth;
- lasth = -lasth;
- }
-
- /* if very small use canned dot */
- if (lastw < LATEX_dotsize || lasth < LATEX_dotsize)
- fprintf(outfile, "\\put(%d,%d){%s}\n",
- (int)lastx, (int)lasty, LATEX_DOT);
- else
- fprintf(outfile, "\\put(%d,%d){\\rule[%.3fpt]{%.3fpt}{%.3fpt}}\n",
- (int)lastx, (int)lasty, -LATEX_dotsize*LATEX_UNIT/2,
- lastw*LATEX_UNIT, lasth*LATEX_UNIT);
- }
-
- if (flush) {
- valid = FALSE;
- } else {
- lastx = x; lasty = y;
- lastw = width; lasth = height;
- valid = TRUE;
- }
- }
-
- static void
- LATEX_dot_line(x1,x2, y1,y2)
- int x1,x2, y1,y2;
- {
- static float LATEX_left; /* fraction of space left after last dot */
- #ifndef AMIGA_AC_5
- extern double sqrt();
- #endif
- /* we draw a dotted line using the current dot spacing */
-
- if (LATEX_moved)
- LATEX_left = 1.0; /* reset after a move */
-
- /* zero-length line? */
- if (x1 == x2 && y1 == y2) {
- if (LATEX_moved)
- /* plot a dot */
- fprintf(outfile, "\\put(%u,%u){%s}\n", x1, y1, LATEX_DOT);
- } else {
- float dotspace = LATEX_dotspace / LATEX_UNIT;
- float x,y; /* current position */
- float xinc, yinc; /* increments */
- float slope; /* slope of line */
- float lastx = -1; /* last x point plotted */
- float lasty = -1; /* last y point plotted */
-
- /* first, figure out increments for x and y */
- if (x2 == x1) {
- xinc = 0.0;
- yinc = dotspace;
- } else {
- slope = ((float)y2-y1)/((float)x2-x1);
- xinc = dotspace / sqrt(1 + slope*slope) * sign(x2-x1);
- yinc = slope * xinc;
- }
-
- /* now draw the dotted line */
- /* we take into account where we last placed a dot */
- for (x=x1 + xinc*(1-LATEX_left), y=y1 + yinc*(1-LATEX_left);
- (x2-x)*xinc >= 0 && (y2-y)*yinc >= 0; /* same sign or zero */
- lastx = x, x += xinc,
- lasty = y, y += yinc)
- fprintf(outfile, "\\put(%d,%d){%s}\n", (int)x, (int)y, LATEX_DOT);
-
- /* how much is left over, as a fraction of dotspace? */
- if (xinc != 0.0) /* xinc must be nonzero */
- if (lastx >= 0)
- LATEX_left = abs(x2 - lastx) / abs(xinc);
- else
- LATEX_left += abs(x2-x1) / abs(xinc);
- else
- if (lasty >= 0)
- LATEX_left = abs(y2 - lasty) / abs(yinc);
- else
- LATEX_left += abs(y2-y1) / abs(yinc);
- }
-
- LATEX_needsdot = (LATEX_left > 0);
-
- LATEX_moved = FALSE;
- }
-
- static void
- LATEX_flushdot()
- {
- if (LATEX_needsdot)
- fprintf(outfile, "\\put(%d,%d){%s}\n",
- LATEX_posx, LATEX_posy, LATEX_DOT);
- LATEX_needsdot = FALSE;
- }
-
- LATEX_arrow(sx,sy, ex,ey, head)
- int sx,sy, ex,ey;
- BOOLEAN head;
- {
- best_latex_arrow(sx,sy, ex,ey, 1, head);
-
- LATEX_posx = ex;
- LATEX_posy = ey;
- }
-
- static void best_latex_arrow(sx,sy, ex,ey, who, head)
- int sx,sy, ex,ey; /* start and end points */
- int who; /* 1=LATEX, 2=EEPIC */
- BOOLEAN head;
- {
- int dx = ex - sx;
- int dy = ey - sy;
- int x, y; /* points near sx,sy */
- float m; /* slope of line */
- float arrowslope; /* slope of arrow */
- float minerror = 0; /* best-case error */
- struct vslope *slope; /* one of the slopes */
- struct vslope *bestslope; /* the slope with min error */
- BOOLEAN horiz; /* was it the horiz line that was best? */
-
- /* We try to draw a real arrow (ie, \vector). If we can't get
- * a slope that is close, we draw a bent arrow.
- */
-
- if (dx == 0) {
- /* vertical arrow */
- fprintf(outfile, "\\put(%d,%d){\\%s(0,%d){%d}}\n",
- sx, sy, head ? "vector":"line",
- sign(ey-sy), abs(ey-sy));
- } else if (dy == 0) {
- /* horizontal arrow */
- fprintf(outfile, "\\put(%d,%d){\\%s(%d,0){%d}}\n",
- sx, sy, head ? "vector":"line",
- sign(ex-sx), abs(ex-sx));
- } else {
- /* Slanted arrow. We'll give it a try.
- * we try to find the closest-slope arrowhead.
- */
- bestslope = NULL;
- minerror = 0; /* to shut up turbo C */
- m = abs((float)dy/dx); /* the slope we want */
- for (slope = LATEX_slopes; slope->dx != 0.0; slope++) {
- /* find the slope of the arrow */
- arrowslope = (float) slope->dy / slope->dx;
- if (bestslope == NULL || abs(m-arrowslope) < minerror) {
- minerror = abs(m-arrowslope);
- bestslope = slope;
- }
- }
-
- /* now we have the best slope arrow */
- /* maybe it's exactly the right slope! */
- if (minerror == 0.0) /* unlikely but possible */
- fprintf(outfile, "\\put(%d,%d){\\%s(%d,%d){%d}}\n",
- sx, sy, head ? "vector" : "line",
- bestslope->dx*sign(ex-sx), bestslope->dy*sign(ey-sy),
- abs(ex-sx));
- else {
- /* we draw the line the usual way, with thin lines */
- #ifdef EMTEX
- if (emtex) {
- LATEX_linetype(LATEX_THIN_LINE);
- EMTEX_solid_line(sx,ex,sy,ey);
- } else
- #endif
- if (who == 1) {
- LATEX_linetype(LATEX_THIN_LINE);
- LATEX_solid_line(sx,ex,sy,ey);
- }
- #ifdef EEPIC
- else {
- EEPIC_move(sx,sy);
- EEPIC_vector(ex,ey);
- }
- #endif /* EEPIC */
- /* and then draw an arrowhead (a short vector) there */
- if (head)
- fprintf(outfile, "\\put(%d,%d){\\vector(%d,%d){0}}\n",
- ex, ey,
- bestslope->dx*sign(ex-sx), bestslope->dy*sign(ey-sy));
- }
- }
- }
-
-
- LATEX_put_text(x, y, str)
- int x,y; /* reference point of string */
- char str[]; /* the text */
- {
- /* ignore empty strings */
- if (str[0] == '\0')
- return;
-
- fprintf(outfile, "\\put(%d,%d)",x,y);
- switch(latex_angle) {
- case 0: {
- switch(latex_justify) {
- case LEFT: {
- fprintf(outfile,
- "{\\makebox(0,0)[l]{%s}}\n", str);
- break;
- }
- case CENTRE: {
- fprintf(outfile,
- "{\\makebox(0,0){%s}}\n", str);
- break;
- }
- case RIGHT: {
- fprintf(outfile,
- "{\\makebox(0,0)[r]{%s}}\n", str);
- break;
- }
- }
- break;
- }
- case 1: { /* put text in a short stack */
- switch(latex_justify) {
- case LEFT: {
- fprintf(outfile,
- "{\\makebox(0,0)[lb]{\\shortstack{%s}}}\n", str);
- break;
- }
- case CENTRE: {
- fprintf(outfile,
- "{\\makebox(0,0)[l]{\\shortstack{%s}}}\n", str);
- break;
- }
- case RIGHT: {
- fprintf(outfile,
- "{\\makebox(0,0)[lt]{\\shortstack{%s}}}\n", str);
- break;
- }
- }
- break;
- }
- }
- }
-
-
-
- int LATEX_justify_text(mode)
- enum JUSTIFY mode;
- {
- latex_justify = mode;
- return (TRUE);
- }
-
- int LATEX_text_angle(angle)
- int angle;
- {
- /* we can't really write text vertically, but this will
- put the ylabel centred at the left of the plot, and
- then we'll make a \shortstack */
- latex_angle = angle;
- return (TRUE);
- }
-
- LATEX_reset()
- {
- LATEX_posx = LATEX_posy = 0; /* current position */
- LATEX_moved = TRUE; /* pen is up after move */
- }
-
-
- #ifdef EMTEX
-
- EMTEX_init()
- {
- emtex=TRUE;
- LATEX_posx = LATEX_posy = 0;
- fprintf(outfile, "%% GNUPLOT: LaTeX picture with emtex specials\n");
- fprintf(outfile, "\\setlength{\\unitlength}{%fpt}\n", LATEX_UNIT);
- fprintf(outfile,
- "\\ifx\\plotpoint\\undefined\\newsavebox{\\plotpoint}\\fi\n");
- LATEX_linetype(-1);
- }
-
-
- EMTEX_reset()
- {
- emtex=FALSE;
- LATEX_posx = LATEX_posy = 0;
- }
-
-
- EMTEX_text()
- {
- fprintf(outfile, "\\end{picture}\n");
- }
-
-
- static void
- EMTEX_solid_line(x1,x2, y1,y2)
- int x1,x2, y1,y2;
- {
- /* emtex special solid line */
- if (LATEX_moved)
- fprintf(outfile, "\\put(%d,%d){\\special{em:moveto}}\n", x1, y1);
- if ( (x1!=x2) || (y1!=y2) )
- fprintf(outfile, "\\put(%d,%d){\\special{em:lineto}}\n", x2, y2);
- LATEX_posx = x2;
- LATEX_posy = y2;
- LATEX_moved = FALSE;
- }
-
-
- #endif /* EMTEX */
-